home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Programming / tek / kn / amiga / exec.c next >
Encoding:
C/C++ Source or Header  |  2001-05-13  |  13.7 KB  |  764 lines

  1.  
  2. /*
  3. **    TEKlib
  4. **    (C) 2001 TEK neoscientists
  5. **    all rights reserved.
  6. **
  7. **    AmigaOS 3.x kernel backend
  8. */
  9.  
  10. #include "tek/type.h"
  11. #include "tek/kn/exec.h"
  12. #include "tek/kn/amiga/exec.h"
  13.  
  14. #include <string.h>
  15. #include <exec/memory.h>
  16. #include <proto/exec.h>
  17. #include <proto/dos.h>
  18. #include <proto/timer.h>
  19. #include <dos/dostags.h>
  20.  
  21. #ifdef __MORPHOS__
  22. #include <emul/emulinterface.h>
  23. #endif
  24.  
  25.  
  26. #define SysBase *((struct ExecBase **) 4L)
  27.  
  28.  
  29. /* 
  30. **    MEMORY ALLOCATION
  31. **
  32. */
  33.  
  34. TAPTR kn_alloc(TUINT size)
  35. {
  36.     TUINT *mem = AllocVec(size + 4, MEMF_ANY);
  37.     if (mem)
  38.     {
  39.         *mem = size;
  40.         return (TAPTR) (mem + 1);
  41.     }
  42.     return TNULL;
  43. }
  44.  
  45.  
  46. TAPTR kn_alloc0(TUINT size)
  47. {
  48.     TUINT *mem = AllocVec(size + 4, MEMF_ANY|MEMF_CLEAR);
  49.     if (mem)
  50.     {
  51.         *mem = size;
  52.         return (TAPTR) (mem + 1);
  53.     }
  54.     return TNULL;
  55. }
  56.  
  57.  
  58. TVOID kn_free(TAPTR mem)
  59. {
  60.     FreeVec(((ULONG *) mem) - 1);
  61. }
  62.  
  63.  
  64. TAPTR kn_realloc(TAPTR oldmem, TUINT newsize)
  65. {
  66.     TUINT *newmem = TNULL;
  67.  
  68.     if (newsize)
  69.     {
  70.         newmem = AllocVec((ULONG) (newsize + 4), MEMF_ANY|MEMF_PUBLIC);
  71.     }
  72.  
  73.     if (oldmem)
  74.     {
  75.         if (newmem)
  76.         {
  77.             ULONG oldsize = *(((ULONG *) oldmem) - 1);
  78.             *newmem = newsize;
  79.             CopyMemQuick(oldmem, newmem+1, TMIN(oldsize, newsize));
  80.         }
  81.         FreeVec(((ULONG *) oldmem) - 1);
  82.     }
  83.  
  84.     if (newmem)
  85.     {
  86.         return (TAPTR) (newmem + 1);
  87.     }
  88.     return TNULL;
  89. }
  90.  
  91.  
  92. TUINT kn_getsize(TAPTR mem)
  93. {
  94.     return (TUINT) *(((ULONG *) mem) - 1);
  95. }
  96.  
  97.  
  98.  
  99. /* 
  100. **    MEMORY MANIPULATION
  101. **
  102. */
  103.  
  104. TVOID kn_memcopy(TAPTR from, TAPTR to, TUINT numbytes)
  105. {
  106.     CopyMem(from, to, (ULONG) numbytes);
  107. }
  108.  
  109.  
  110. TVOID kn_memcopy32(TAPTR from, TAPTR to, TUINT numbytes)
  111. {
  112.     CopyMemQuick(from, to, (ULONG) numbytes);
  113. }
  114.  
  115.  
  116. TVOID kn_memset(TAPTR dest, TUINT numbytes, TUINT8 fillval)
  117. {
  118.     memset(dest, (int) fillval, numbytes);
  119. }
  120.  
  121.  
  122. TVOID kn_memset32(TAPTR dest, TUINT numbytes, TUINT fillval)
  123. {
  124.     TUINT i, *m = dest;
  125.     for (i = 0; i < numbytes >> 2; ++i)
  126.     {
  127.         *m++ = fillval;
  128.     }
  129. }
  130.  
  131.  
  132.  
  133. /* 
  134. **    LOCK
  135. **
  136. */
  137.  
  138. TBOOL kn_initlock(TKNOB *lock)
  139. {
  140.     if (sizeof(TKNOB) >= sizeof(struct SignalSemaphore))
  141.     {
  142.         kn_memset(lock, sizeof(struct SignalSemaphore), 0);
  143.         InitSemaphore((struct SignalSemaphore *) lock);
  144.         return TTRUE;
  145.     }
  146.     else
  147.     {
  148.         struct SignalSemaphore *sem = kn_alloc0(sizeof(struct SignalSemaphore));
  149.         if (sem)
  150.         {
  151.             InitSemaphore(sem);
  152.             *((struct SignalSemaphore **) lock) = sem;
  153.             return TTRUE;
  154.         }
  155.     }
  156.  
  157.     dbkprintf(20,"*** TEKLIB kernel: could not create lock\n");
  158.     return TFALSE;
  159. }
  160.  
  161.  
  162. TVOID kn_destroylock(TKNOB *lock)
  163. {
  164.     if (sizeof(TKNOB) < sizeof(struct SignalSemaphore))
  165.     {
  166.         kn_free(*((TAPTR *) lock));
  167.     }
  168. }
  169.  
  170.  
  171. TVOID kn_lock(TKNOB *lock)
  172. {
  173.     if (sizeof(TKNOB) >= sizeof(struct SignalSemaphore))
  174.     {
  175.         ObtainSemaphore((struct SignalSemaphore *) lock);
  176.     }
  177.     else
  178.     {
  179.         ObtainSemaphore(*((struct SignalSemaphore **) lock));
  180.     }
  181. }
  182.  
  183.  
  184. TVOID kn_unlock(TKNOB *lock)
  185. {
  186.     if (sizeof(TKNOB) >= sizeof(struct SignalSemaphore))
  187.     {
  188.         ReleaseSemaphore((struct SignalSemaphore *) lock);
  189.     }
  190.     else
  191.     {
  192.         ReleaseSemaphore(*((struct SignalSemaphore **) lock));
  193.     }
  194. }
  195.  
  196.  
  197.  
  198. /* 
  199. **    TIMER
  200. **
  201. */
  202.  
  203. struct amitimer
  204. {
  205.     struct MsgPort *msgport;
  206.     struct timerequest *timereq;
  207.     struct timeval tv;
  208. };
  209.  
  210. TBOOL kn_inittimer(TKNOB *timer)
  211. {
  212.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  213.     {
  214.         struct amitimer *t = (struct amitimer *) timer;
  215.         t->msgport = CreateMsgPort();
  216.         if (t->msgport)
  217.         {
  218.             t->timereq = (struct timerequest *) CreateIORequest(t->msgport, sizeof(struct timerequest));
  219.             if (t->timereq)
  220.             {
  221.                 if (!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) t->timereq, 0))
  222.                 {
  223.                     #define TimerBase (struct Device *) t->timereq->tr_node.io_Device
  224.                     ReadEClock((struct EClockVal *) &t->tv);
  225.                     #undef TimerBase
  226.                     return TTRUE;
  227.                 }
  228.                 DeleteIORequest(t->timereq);
  229.             }
  230.             DeleteMsgPort(t->msgport);
  231.         }
  232.     }
  233.     else
  234.     {
  235.         struct amitimer *t = kn_alloc(sizeof(struct amitimer));
  236.         if (t)
  237.         {
  238.             t->msgport = CreateMsgPort();
  239.             if (t->msgport)
  240.             {
  241.                 t->timereq = (struct timerequest *) CreateIORequest(t->msgport, sizeof(struct timerequest));
  242.                 if (t->timereq)
  243.                 {
  244.                     if (!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) t->timereq, 0))
  245.                     {
  246.                         #define TimerBase (struct Device *) t->timereq->tr_node.io_Device
  247.                         ReadEClock((struct EClockVal *) &t->tv);
  248.                         #undef TimerBase
  249.                         *((struct amitimer **) timer) = t;
  250.                         return TTRUE;
  251.                     }
  252.                     DeleteIORequest(t->timereq);
  253.                 }
  254.                 DeleteMsgPort(t->msgport);
  255.             }
  256.             kn_free(t);
  257.         }
  258.     }
  259.  
  260.     dbkprintf(20,"*** TEKLIB kernel: could not create timer\n");
  261.     return TFALSE;
  262. }
  263.  
  264.  
  265. TVOID kn_destroytimer(TKNOB *timer)
  266. {
  267.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  268.     {
  269.         struct amitimer *t = (struct amitimer *) timer;
  270.         CloseDevice((struct IORequest *) t->timereq);
  271.         DeleteIORequest(t->timereq);
  272.         DeleteMsgPort(t->msgport);
  273.     }
  274.     else
  275.     {
  276.         struct amitimer *t = *((struct amitimer **) timer);
  277.         CloseDevice((struct IORequest *) t->timereq);
  278.         DeleteIORequest(t->timereq);
  279.         DeleteMsgPort(t->msgport);
  280.         kn_free(t);
  281.     }
  282. }
  283.  
  284.  
  285. TVOID kn_querytimer(TKNOB *timer, TTIME *tektime)
  286. {
  287.     struct amitimer *t;
  288.     float freq, sec;
  289.  
  290.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  291.     {
  292.         t = (struct amitimer *) timer;
  293.     }
  294.     else
  295.     {
  296.         t = *((struct amitimer **) timer);
  297.     }
  298.     
  299.     #define TimerBase (struct Device *) t->timereq->tr_node.io_Device
  300.  
  301.     freq = ReadEClock((struct EClockVal *) tektime);
  302.  
  303.     if (tektime->usec < t->tv.tv_micro)
  304.     {
  305.         sec = (tektime->sec - t->tv.tv_secs - 1) * freq + (tektime->usec - t->tv.tv_micro) / freq;
  306.     }
  307.     else
  308.     {
  309.         sec = (tektime->sec - t->tv.tv_secs) * freq + (tektime->usec - t->tv.tv_micro) / freq;
  310.     }
  311.     
  312.     tektime->sec = (TUINT) sec;
  313.     tektime->usec = (sec - tektime->sec) * 1000000;
  314.  
  315.     #undef TimerBase
  316. }
  317.  
  318.  
  319. TVOID kn_timedelay(TKNOB *timer, TTIME *tektime)
  320. {
  321.     struct amitimer *t;
  322.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  323.     {
  324.         t = (struct amitimer *) timer;
  325.     }
  326.     else
  327.     {
  328.         t = *((struct amitimer **) timer);
  329.     }
  330.  
  331.     t->timereq->tr_node.io_Command = TR_ADDREQUEST;
  332.     t->timereq->tr_time.tv_secs = tektime->sec;
  333.     t->timereq->tr_time.tv_micro = tektime->usec;
  334.                 
  335.     DoIO((struct IORequest *) t->timereq);
  336. }
  337.  
  338.  
  339. TVOID kn_resettimer(TKNOB *timer)
  340. {
  341.     struct amitimer *t;
  342.  
  343.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  344.     {
  345.         t = (struct amitimer *) timer;
  346.     }
  347.     else
  348.     {
  349.         t = *((struct amitimer **) timer);
  350.     }
  351.     
  352.     #define TimerBase (struct Device *) t->timereq->tr_node.io_Device
  353.  
  354.     ReadEClock((struct EClockVal *) &t->tv);
  355.  
  356.     #undef TimerBase
  357. }
  358.  
  359.  
  360.  
  361. /* 
  362. **    EVENT
  363. **
  364. */
  365.  
  366. TBOOL kn_initevent(TKNOB *event)
  367. {
  368.     if (sizeof(TKNOB) >= sizeof(struct amievent))
  369.     {
  370.         struct amievent *evt = (struct amievent *) event;
  371.         evt->signal = AllocSignal(-1);
  372.         if (evt->signal > -1)
  373.         {
  374.             evt->task = FindTask(NULL);
  375.             return TTRUE;
  376.         }
  377.     }
  378.     else
  379.     {
  380.         struct amievent *evt = kn_alloc(sizeof(struct amievent));
  381.         if (evt)
  382.         {
  383.             evt->signal = AllocSignal(-1);
  384.             if (evt->signal > -1)
  385.             {
  386.                 evt->task = FindTask(NULL);
  387.                 *((struct amievent **) event) = evt;
  388.                 return TTRUE;
  389.             }
  390.  
  391.             kn_free(evt);
  392.         }
  393.     }
  394.  
  395.     dbkprintf(20,"*** TEKLIB kernel: could not create event\n");
  396.     return TFALSE;
  397. }
  398.  
  399.  
  400. TVOID kn_destroyevent(TKNOB *event)
  401. {
  402.     if (sizeof(TKNOB) >= sizeof(struct amievent))
  403.     {
  404.         FreeSignal((long)((struct amievent *) event)->signal);
  405.     }
  406.     else
  407.     {
  408.         FreeSignal((long)(*((struct amievent **) event))->signal);
  409.         kn_free(*((TAPTR *) event));
  410.     }
  411. }
  412.  
  413.  
  414. TVOID kn_doevent(TKNOB *event)
  415. {
  416.     struct amievent *evt;
  417.  
  418.     if (sizeof(TKNOB) >= sizeof(struct amievent))
  419.     {
  420.         evt = (struct amievent *) event;
  421.     }
  422.     else
  423.     {
  424.         evt = *((struct amievent **) event);
  425.     }
  426.  
  427.     Signal(evt->task, 1L << evt->signal);
  428. }
  429.  
  430.  
  431. TVOID kn_waitevent(TKNOB *event)
  432. {
  433.     struct amievent *evt;
  434.  
  435.     if (sizeof(TKNOB) >= sizeof(struct amievent))
  436.     {
  437.         evt = (struct amievent *) event;
  438.     }
  439.     else
  440.     {
  441.         evt = *((struct amievent **) event);
  442.     }
  443.  
  444.     Wait(1L << (evt->signal));
  445. }
  446.  
  447.  
  448. TBOOL kn_timedwaitevent(TKNOB *event, TKNOB *timer, TTIME *tektime)
  449. {
  450.     struct amievent *evt;
  451.     struct amitimer *tim;
  452.     TBOOL occured;
  453.  
  454.     if (sizeof(TKNOB) >= sizeof(struct amievent))
  455.     {
  456.         evt = (struct amievent *) event;
  457.     }
  458.     else
  459.     {
  460.         evt = *((struct amievent **) event);
  461.     }
  462.  
  463.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  464.     {
  465.         tim = (struct amitimer *) timer;
  466.     }
  467.     else
  468.     {
  469.         tim = *((struct amitimer **) timer);
  470.     }
  471.  
  472.     if (tektime)
  473.     {
  474.         tim->timereq->tr_node.io_Command = TR_ADDREQUEST;
  475.         tim->timereq->tr_time.tv_secs = tektime->sec;
  476.         tim->timereq->tr_time.tv_micro = tektime->usec;
  477.                     
  478.         SendIO((struct IORequest *) tim->timereq);
  479.     
  480.         occured = Wait((1L << (evt->signal)) | (1L << tim->msgport->mp_SigBit)) & (1L << evt->signal);
  481.     
  482.         AbortIO((struct IORequest *) tim->timereq);
  483.         WaitIO((struct IORequest *) tim->timereq);
  484.         SetSignal(0, 1L << tim->msgport->mp_SigBit);
  485.     }
  486.     else
  487.     {
  488.         occured = SetSignal(0, 1 << evt->signal) & (1 << evt->signal);
  489.     }
  490.  
  491.     return occured;
  492. }
  493.  
  494.  
  495.  
  496. /* 
  497. **    THREAD
  498. **
  499. */
  500.  
  501. static void amithread_entry(void)
  502. {
  503.     struct Task *self = FindTask(NULL);
  504.     struct MsgPort *childinitport = &((struct Process *) self)->pr_MsgPort;
  505.     struct amithread *thread;
  506.  
  507.     dbkprintf(3,"*** TEKLIB kernel: entering child context\n");
  508.  
  509.     /*
  510.     **    wait for the init data packet
  511.     */
  512.  
  513.     WaitPort(childinitport);
  514.     thread = (struct amithread *) GetMsg(childinitport);
  515.     if (!thread)
  516.     {
  517.         dbkprintf(40,"*** TEKLIB amithread_entry: ALERT - NO THREAD\n");
  518.     }
  519.  
  520.     /* 
  521.     **    self reference
  522.     */
  523.  
  524.     self->tc_UserData = thread;
  525.  
  526.     /*
  527.     **    acknowledge init package
  528.     */
  529.     
  530.     ReplyMsg((struct Message *) thread);
  531.  
  532.     /* 
  533.     **    additional initializations in child context
  534.     */
  535.  
  536.     thread->dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 0);
  537.  
  538.     /*
  539.     **    call user function
  540.     */
  541.     
  542.     (*thread->function)(thread->data);
  543. }
  544.  
  545. #ifdef __MORPHOS__
  546. struct EmulLibEntry amithread_GATE = { TRAP_LIBNR, 0, (void (*)(void))amithread_entry };
  547. #endif
  548.  
  549. TBOOL kn_initbasecontext(TKNOB *thread, TAPTR selfdata)
  550. {
  551.     if (sizeof(TKNOB) >= sizeof(struct amithread))
  552.     {
  553.         struct amithread *t = (struct amithread *) thread;
  554.         kn_memset(t, sizeof(struct amithread), 0);
  555.         
  556.         t->dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 0);
  557.  
  558.         t->data = selfdata;
  559.         (FindTask(NULL))->tc_UserData = t;
  560.  
  561.         return TTRUE;
  562.     }
  563.     else
  564.     {
  565.         struct amithread *t = kn_alloc0(sizeof(struct amithread));
  566.         if (t)
  567.         {
  568.             t->dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 0);
  569.  
  570.             t->data = selfdata;
  571.             (FindTask(NULL))->tc_UserData = t;
  572.  
  573.             *((struct amithread **) thread) = t;
  574.  
  575.             return TTRUE;
  576.         }    
  577.     }    
  578.  
  579.     dbkprintf(20,"*** TEKLIB kernel: could not establish basecontext\n");
  580.     return TFALSE;
  581. }
  582.  
  583.  
  584. TVOID kn_destroybasecontext(TKNOB *thread)
  585. {
  586.     if (sizeof(TKNOB) >= sizeof(struct amithread))
  587.     {
  588.         CloseLibrary(((struct amithread *) thread)->socketbase);
  589.         CloseLibrary((struct Library *) ((struct amithread *) thread)->dosbase);
  590.     }
  591.     else
  592.     {
  593.         CloseLibrary((*((struct amithread **) thread))->socketbase);
  594.         CloseLibrary((struct Library *) (*((struct amithread **) thread))->dosbase);
  595.         kn_free(*((struct amithread **) thread));
  596.     }
  597. }
  598.  
  599. TBOOL kn_initthread(TKNOB *thread, TVOID (*function)(TAPTR task), TAPTR selfdata)
  600. {
  601.     TBOOL success = FALSE;
  602.  
  603.     if (sizeof(TKNOB) >= sizeof(struct amithread))
  604.     {
  605.         struct amithread *t = (struct amithread *) thread;
  606.         kn_memset(t, sizeof(struct amithread), 0);
  607.  
  608.         t->initreplyport = CreateMsgPort();
  609.         if (t->initreplyport)
  610.         {
  611.             struct amithread *self = (struct amithread *) FindTask(NULL)->tc_UserData;
  612.             #define DOSBase self->dosbase
  613.         
  614. #ifdef __MORPHOS__
  615.             t->childproc = CreateNewProcTags(NP_Entry, (ULONG) &amithread_GATE, TAG_DONE);
  616. #else
  617.             t->childproc = CreateNewProcTags(NP_Entry, (ULONG) amithread_entry, TAG_DONE);
  618. #endif
  619.             if (t->childproc)
  620.             {
  621.                 t->message.mn_ReplyPort = t->initreplyport;
  622.                 t->message.mn_Length = sizeof(struct amithread);
  623.                 t->function = function;
  624.                 t->data = selfdata;
  625.  
  626.                 /*
  627.                 **    put initial data packet to the thread
  628.                 */
  629.             
  630.                 PutMsg(&t->childproc->pr_MsgPort, (struct Message *) t);
  631.  
  632.                 /*
  633.                 **    wait for confirmation
  634.                 */
  635.             
  636.                 WaitPort(t->initreplyport);
  637.                 GetMsg(t->initreplyport);
  638.  
  639.                 success = TTRUE;
  640.             }
  641.             DeleteMsgPort(t->initreplyport);
  642.             
  643.             #undef DOSBase
  644.         }
  645.     }
  646.     else
  647.     {
  648.         struct amithread *t = kn_alloc0(sizeof(struct amithread));
  649.         if (t)
  650.         {
  651.             t->initreplyport = CreateMsgPort();
  652.             if (t->initreplyport)
  653.             {
  654.                 struct amithread *self = (struct amithread *) FindTask(NULL)->tc_UserData;
  655.                 #define DOSBase self->dosbase
  656.  
  657. #ifdef __MORPHOS__
  658.                 t->childproc = CreateNewProcTags(NP_Entry, (ULONG) &amithread_GATE, TAG_DONE);
  659. #else
  660.                 t->childproc = CreateNewProcTags(NP_Entry, (ULONG) amithread_entry, TAG_DONE);
  661. #endif
  662.                 if (t->childproc)
  663.                 {
  664.                     t->message.mn_ReplyPort = t->initreplyport;
  665.                     t->message.mn_Length = sizeof(struct amithread);
  666.                     t->function = function;
  667.                     t->data = selfdata;
  668.  
  669.                     /*
  670.                     **    put initial data packet to the thread
  671.                     */
  672.                 
  673.                     PutMsg(&t->childproc->pr_MsgPort, (struct Message *) t);
  674.  
  675.                     /*
  676.                     **    wait for confirmation
  677.                     */
  678.                 
  679.                     WaitPort(t->initreplyport);
  680.                     GetMsg(t->initreplyport);
  681.  
  682.                     *((struct amithread **) thread) = t;
  683.  
  684.                     success = TTRUE;
  685.                 }
  686.                 DeleteMsgPort(t->initreplyport);
  687.  
  688.                 #undef DOSBase
  689.             }
  690.             
  691.             if (!success)
  692.             {
  693.                 kn_free(t);
  694.             }
  695.         }
  696.     }
  697.  
  698.     if (!success)
  699.     {
  700.         dbkprintf(20,"*** TEKLIB kernel: could not create thread\n");
  701.     }    
  702.     return success;
  703. }
  704.  
  705.  
  706. TVOID kn_deinitthread(TKNOB *thread)
  707. {
  708.     if (sizeof(TKNOB) >= sizeof(struct amithread))
  709.     {
  710.         CloseLibrary((struct Library *) ((struct amithread *) thread)->dosbase);
  711.         CloseLibrary(((struct amithread *) thread)->socketbase);
  712.     }
  713.     else
  714.     {
  715.         CloseLibrary((struct Library *) (*((struct amithread **) thread))->dosbase);
  716.         CloseLibrary((*((struct amithread **) thread))->socketbase);
  717.     }
  718. }
  719.  
  720.  
  721. TVOID kn_destroythread(TKNOB *thread)
  722. {
  723.     if (sizeof(TKNOB) < sizeof(struct amithread))
  724.     {
  725.         kn_free(*((struct amithread **) thread));
  726.     }
  727. }
  728.  
  729.  
  730. TAPTR kn_findself(TVOID)
  731. {
  732.     return (TAPTR) ((struct amithread *) ((FindTask(NULL))->tc_UserData))->data;
  733. }
  734.  
  735.  
  736.  
  737. TINT kn_getrandomseed(TKNOB *timer)
  738. {
  739.     struct amitimer *t;
  740.     struct EClockVal time;
  741.  
  742.     if (sizeof(TKNOB) >= sizeof(struct amitimer))
  743.     {
  744.         t = (struct amitimer *) timer;
  745.     }
  746.     else
  747.     {
  748.         t = *((struct amitimer **) timer);
  749.     }
  750.     
  751.     #define TimerBase (struct Device *) t->timereq->tr_node.io_Device
  752.  
  753.     ReadEClock(&time);
  754.  
  755.     #undef TimerBase
  756.     
  757.     return (TINT) time.ev_lo;
  758. }
  759.  
  760.  
  761.  
  762. #undef SysBase
  763.  
  764.